package com.cxdr.awsips.distribute.file;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.regex.Pattern;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import org.apache.log4j.Logger;

import com.cxdr.awsips.common.logger.LogFactory;
import com.cxdr.awsips.distribute.bean.ReportFileLog;
import com.cxdr.awsips.distribute.bean.Target;
import com.cxdr.awsips.distribute.net.FTPUtils;
import com.cxdr.awsips.distribute.rule.FileNameRule;
import com.cxdr.awsips.distribute.rule.TimeRule;

public class FTPFileHelper implements FileHelper {
	private static Logger logger = LogFactory
			.makeNewLogger(FTPFileHelper.class);
	private FTPClient ftpClient;
	private Target target;
	private String HOME_WORK;
	private String localDir;
	private String remoteDir;
	private String remoteFileSeparator = "/";
//	private FileNameRule fileNameRule;
//	private TimeRule timeRule;
	private List<FileNameRule> fileNameRules = new ArrayList<FileNameRule>();
//	private List<StationRule> stationRules = new ArrayList<StationRule>();
	private List<TimeRule> timeRules = new ArrayList<TimeRule>();
	private long keyTime;
	private boolean sub;
	public FTPFileHelper(FTPClient ftpClient) {
		this.ftpClient = ftpClient;
		init(this.ftpClient);
	}

	public FTPFileHelper(Target target) throws IOException {
		this.target = target;
		remoteDir = target.getFolder();
	//	open();
	//	setRemoteDir(target.getFolder());
	}

	private void init(FTPClient ftpClient) {
		if (StringUtils.isBlank(localDir)) {
			localDir = System.getProperty("user.dir");
		}
		logger.info("init");
		this.ftpClient = ftpClient;
		try {
			HOME_WORK = ftpClient.printWorkingDirectory();
			// 特定于类unix系统
			if (HOME_WORK.equals("/")) {
				HOME_WORK = "";
			}
			String ftpSystemType = ftpClient.getSystemType();
			logger.info(ftpSystemType);
			if (ftpSystemType.contains("UNIX")) {
				remoteFileSeparator = "/";
			} else {
				remoteFileSeparator = "\\";
			}
			if (StringUtils.isBlank(remoteDir)) {
				remoteDir = ftpClient.printWorkingDirectory();
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	@Override
	public void open() throws IOException {
		if(target!=null){
			init(FTPUtils.loginFtp(target.getIp(), target.getUser_name(),
					target.getPass()));
		}else{
			init(ftpClient);
		}
	}

	public void close() {
		FTPClient ftp = getFtpClient();
		if (ftp != null && ftp.isConnected()) {
			try {
				ftp.logout();
				ftp.disconnect();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	public void getDir(String dir) {
		FTPClient ftp = getFtpClient();
		if (ftp == null || !ftp.isConnected() || !ftp.isAvailable()) {
			logger.info("ftp can not be available");
			return;
		}
		if (!(dir == null || dir.length() == 0)) {
			try {
				Set<String> remoteFileNames = new TreeSet<String>();
				if (ftp.cwd(dir) == FTPReply.FILE_ACTION_OK) {
					FTPFile[] ftpFiles = ftp.listFiles();
					for (FTPFile ftpFile : ftpFiles) {
						if (ftpFile.isFile()
								&& ftpFile.getName().contains("txt")) {
							remoteFileNames.add(ftpFile.getName());
						}
					}
				}
				File localDir = new File(getLocalDir() + File.separator + dir);
				if (!localDir.exists()) {
					localDir.mkdirs();
				}
				// logger.info(localDir.getAbsolutePath());
				// setLocalDir(localDir.getAbsolutePath());
				for (String remoteFileName : remoteFileNames) {
					logger.info(remoteFileName);
					getFile(remoteFileName);
				}
				logger.info(ftp.getReplyString());
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * @param 服务器上的文件名
	 * 下载到本地目录，在下载前需要设置localDir,否则默认是用户工作目录
	 */
	public File getFile(String fileName) {
		FTPClient ftp = getFtpClient();
		if (ftp == null || !ftp.isConnected() || !ftp.isAvailable()) {
			logger.info("ftp can not be available");
			return null;
		}
		// ftp.setControlEncoding("gbk");
		File localDir = new File(getLocalDir());
		if (!localDir.isDirectory()) {
			localDir.mkdirs();
		}
		File _localFile = new File(getLocalDir() + File.separator + fileName);
		if (_localFile.exists() && _localFile.isFile()) {
			if (!_localFile.canWrite()) {
				logger.info("file can not wirte");
				return null;
			}
			_localFile.delete();
		}
		try {
			ByteArrayOutputStream buffer = new ByteArrayOutputStream();
			BufferedOutputStream bos = new BufferedOutputStream(buffer);
			fileName = new String(fileName.getBytes("gbk"), "ISO-8859-1");
			String _remoteFile = fileName;//getRemoteDir() + remoteFileSeparator
			if (ftp.retrieveFile(fileName, bos)) {
				BufferedOutputStream fileBuffer = new BufferedOutputStream(
						new FileOutputStream(_localFile));
				bos.flush();
				buffer.writeTo(fileBuffer);
				fileBuffer.flush();
				fileBuffer.close();
			} else {
				logger.info("retrieveFile is failed:");
				logger.info(ftp.getReplyString());
			}
			bos.close();
			if (target != null) {
				if (!StringUtils.isBlank(target.getBackpath())) {
					String backFile = target.getBackpath()
							+ remoteFileSeparator + fileName;
					logger.info("备份远程文件：" + _remoteFile);
					if (!ftp.rename(_remoteFile, backFile)) {
						ftp.deleteFile(_remoteFile);
					}
				} else if(keyTime == -1){
					logger.info("删除文件：" + _remoteFile);
					ftp.deleteFile(_remoteFile);
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
			logger.error("downloadFile has a exception", e);
			return null;
		}
		return _localFile;
	}

	public FTPClient getFtpClient() {
		logger.debug("getFtpClient");
		if (!checkFtpStatu(ftpClient)) {
			try {
				logger.info("重新连接FTP");
				ftpClient = FTPUtils.loginFtp(target.getIp(),
						target.getUser_name(), target.getPass());
			} catch (IOException e) {
				logger.error("获取FTP连接出错", e);
			}
		}
		return ftpClient;
	}

	public String getLocalDir() {
		return localDir;
	}

	public String getRemoteDir() {
		return remoteDir;
	}

	public Set<File> scanDir() {
		return scanDir(getRemoteDir());
	}

	public Set<File> scanDir(String dir) {
		return scanDir(dir, "txt");
	}

	public Set<File> scanDir(String dir, String fileType) {
		Set<File> remoteFiles = new TreeSet<File>();
		FTPClient ftp = getFtpClient();
		if (ftp == null || !ftp.isConnected() || !ftp.isAvailable()) {
			logger.info("ftp can not be available");
			return remoteFiles;
		}
		if (dir == null || StringUtils.isBlank(dir)) {
			logger.info("The directory is not a valid directory");
			return remoteFiles;
		}
		_scanDir(remoteFiles,ftp,dir,fileType);
		return remoteFiles;
	}
	private void _scanDir(Set<File> remoteFiles,FTPClient ftp,String dir, String fileType){
		String homeLocalDir = getLocalDir();
		try {
			String workingDir = ftp.printWorkingDirectory();
			logger.info("开始扫描目录" + workingDir+"/"+ dir + "....");
			FTPFile[] ftpFiles = ftp.listFiles(dir);
			logger.info("扫描到 " + ftpFiles.length + "个文件");
			String localDirStr = homeLocalDir;
			logger.info("workingDir:"+workingDir);
			if(isSub()&&!workingDir.equals(HOME_WORK)){
				if(workingDir.equals("/")&&HOME_WORK.equals("")){
				}else{
					localDirStr = homeLocalDir+File.separator+dir;
					setLocalDir(localDirStr);
				}
			}
			File localDir = new File(localDirStr);
			if (!localDir.exists()) {
				localDir.mkdirs();
			}
			// setLocalDir(localDir.getAbsolutePath());
			if(!ftp.changeWorkingDirectory(dir)){
				logger.info("更换目录失败" + dir + "....");
				return;
			}
			Date currentTime = new Date();
			for (FTPFile ftpFile : ftpFiles) {
				if(ftpFile.isDirectory()){
					logger.info("开始扫描目录" + dir + "....");
					_scanDir(remoteFiles,ftp,ftpFile.getName(),fileType);
					continue;
				}
				/*********************过滤源文件****************************/
				String fileName = ftpFile.getName();
				boolean isAccept = true;
				for(FileNameRule fileNameRule:fileNameRules){
					if (fileNameRule != null && !fileNameRule.accept(fileName)) {
						isAccept = false;
						break;
					}
				}
				if(!isAccept) continue;
				Calendar fileTime = ftpFile.getTimestamp();
				for (TimeRule timeRule : timeRules) {
					if (timeRule != null
							&& timeRule.accept(fileTime.getTime())) {
						isAccept = false;
						break;
					}
				}
				if(!isAccept) continue;
				/*************************删除过期文件********************************/
				if(keyTime > 0){
					ReportFileLog fileLog = new ReportFileLog();
					fileLog.setFile_name(fileName, true);
					if(fileLog.getObser_time().getTime()+keyTime < currentTime.getTime()){
						deleteFile(fileName);
						continue;
					}
				}
				logger.info("fileName is :" + fileName);
				if (ftpFile.isFile()) {
					if (StringUtils.isBlank(fileType)
							|| StringUtils.endsWithIgnoreCase(fileName, ".*")) {
						File localFile = getFile(fileName);
						remoteFiles.add(localFile);
						continue;
					}
					if (StringUtils
							.endsWithIgnoreCase(fileName, "." + fileType)) {
						File localFile = getFile(fileName);
						remoteFiles.add(localFile);
					}
				}
			}
			logger.info(ftp.getReplyString());
		} catch (Exception e) {
			logger.error("list file error:", e);
			e.printStackTrace();
		}
		setLocalDir(homeLocalDir);
		try {	String workingDir = ftp.printWorkingDirectory();
				logger.info("workingDir:"+workingDir);
				if(!workingDir.equals(HOME_WORK+"/"+remoteDir)){
					ftp.changeToParentDirectory();
					logger.info("change to parent: "+ftp.printWorkingDirectory());
				}
				logger.info(ftp.getReplyString());
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public void setLocalDir(String localDir) {
		this.localDir = localDir;
	}

	public String getRemoteFileSeparator() {
		return this.remoteFileSeparator;
	}

	/**
	 * 获取ftp的主目录
	 */
	public String getHomeWork() {
		return this.HOME_WORK;
	}

	public void setRemoteDir(String remoteDir) {
		try {
			this.remoteDir = remoteDir;
//			if(HOME_WORK != null){
//				remoteDir = HOME_WORK+remoteFileSeparator+remoteDir;
//			}
			if(!ftpClient.changeWorkingDirectory(remoteDir)){
				ftpClient.mkd(remoteDir);
				ftpClient.changeWorkingDirectory(remoteDir);
			}
			logger.info("remoteDir:"+remoteDir);
		} catch (IOException e) {
			e.printStackTrace();
			logger.error("",e);
		}
		this.remoteDir = remoteDir;
	}

	/**
	 * 复制远程文件 2011-8-23 pugang
	 */
	public boolean renameFile(String from, String to) {
		if (StringUtils.isBlank(from)) {
			logger.error("Trom file name " + from + "is invaild!");
			return false;
		}
		if (StringUtils.isBlank(to)) {
			logger.error("To file name " + to + "is invaild!");
			return false;
		}
		FTPClient ftp = getFtpClient();
		if (checkFtpStatu(ftp)) {
			try {
				boolean result = ftp.rename(from, to);
				return result;
			} catch (IOException e) {
				logger.error("rename file error", e);
				e.printStackTrace();
				return false;
			} finally {
				logger.info(ftp.getReplyString());
			}
		}
		return false;
	}

	/**
	 * 删除远程文件
	 * 
	 * @param fileName
	 * @return
	 */
	public boolean deleteFile(String fileName) {
		if (StringUtils.isBlank(fileName)) {
			logger.error("Trom file name " + fileName + "is invaild!");
			return false;
		}
		logger.info("delete file"+fileName);
		FTPClient ftp = getFtpClient();
		if (checkFtpStatu(ftp)) {
			try {
				boolean result = ftp.deleteFile(fileName);
				return result;
			} catch (IOException e) {
				logger.error("delete file error", e);
				e.printStackTrace();
				return false;
			} finally {
				logger.error(ftp.getReplyString());
			}
		}
		return false;
	}

	public boolean uploadFile(File file) {
		String filePath = file.getAbsolutePath();
		String separator = File.separator;
		if (separator.equals("\\")){
			separator = "\\\\";
		}
		logger.info("file path:"+filePath);
		logger.info("local dir:"+getLocalDir());
		String[] fileRelatePath = file.getAbsolutePath().replace(getLocalDir(), "").split(separator);
		logger.debug("开始上传文件：" + filePath);
		FTPClient ftp = getFtpClient();
		if (!checkFtpStatu(ftp)) {
			logger.error("ftp can not be available");
			if (ftp == null) {
				logger.error("ftp reconnect failed");
				return false;
			}
		}
//		FTPFile[] 
		String currentWorkingDir = "";
		try {
			 currentWorkingDir = ftp.printWorkingDirectory();
			 logger.info("currentWorkingDir: "+currentWorkingDir);
		} catch (IOException e1) {
			e1.printStackTrace();
		}
		try {
			for (String path : fileRelatePath) {
				if(path.endsWith(".java")||StringUtils.isBlank(path)||path.endsWith(".txt")){
					continue;
				}
				if (!ftp.changeWorkingDirectory(path)) {
					ftp.mkd(path);
					ftp.changeWorkingDirectory(path);
				}
			}
		}catch( Exception e){
			logger.error("",e);
			try {
				ftp.changeWorkingDirectory(currentWorkingDir);
			} catch (IOException e1) {
				e1.printStackTrace();
			}
			return false;
		}
		File _localFile = file;//new File(getLocalDir() + File.separator + fileName);
		try{
			if (!_localFile.canRead()) {
				logger.info("file " + _localFile.getAbsolutePath()
						+ " can not be read");
				return false;
			}
			if (!_localFile.exists() || !_localFile.isFile()) {
				logger.info(_localFile.getAbsolutePath() + " is not a file");
				return false;
			}
			try {
				// logger.debug("local req file:"+_localFile);
				String remoteFileName = _localFile.getName();
				logger.info("上传文件:" + remoteFileName);
				InputStream ins = new BufferedInputStream(new FileInputStream(
						_localFile));
				// TODO 有待优化字符编码
				remoteFileName = new String(remoteFileName.getBytes("gbk"),
						"iso-8859-1");
				ftp.storeFile(remoteFileName, ins);
				ins.close();
				logger.info("上传文件:" + remoteFileName + "成功");
			} catch (Exception e) {
				logger.error("write file error:", e);
				// e.printStackTrace();
				return false;
			}
		} finally {
			try {
				ftp.changeWorkingDirectory(currentWorkingDir);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return true;
	}
	
	private boolean checkFtpStatu(FTPClient ftp) {
		try {
			if (ftp == null || !ftp.isConnected() || !ftp.isAvailable()) {
				logger.error("ftp can not be available");
				if(ftp != null){
					ftp.logout();
					ftp.disconnect();
				}
				return false;
			}
			// 测试连接是否可用，如果不可用则产生异常
			logger.debug("checkFtpStatu");
			ftp.list();
			logger.debug("FtpStatu ok");
		} catch (Exception e) {
			logger.error("ftp can not be available", e);
			if(ftp != null){
				try {
					ftp.logout();
					ftp.disconnect();
				} catch (IOException e1) {
					e1.printStackTrace();
				}
			}
			return false;
		}
		return true;
	}

	public List<FileNameRule> getFileNameRules() {
		return fileNameRules;
	}

	public void setFileNameRules(List<FileNameRule> fileNameRules) {
		this.fileNameRules = fileNameRules;
	}

	public List<TimeRule> getTimeRules() {
		return timeRules;
	}

	public void setTimeRules(List<TimeRule> timeRules) {
		this.timeRules = timeRules;
	}

	public long getKeyTime() {
		return keyTime;
	}

	public void setKeyTime(long keyTime) {
		this.keyTime = keyTime;
	}

	public boolean isSub() {
		return sub;
	}

	public void setSub(boolean sub) {
		this.sub = sub;
	}

	public static void main(String[] args) throws Exception {
//		Target t = new Target();
		FTPClient ftpClient = FTPUtils.loginFtp("192.168.0.201", "pugang","pugang");
//		ftpClient
		FTPFileHelper ftp = new FTPFileHelper(ftpClient);
//		ftp.setSub(true);
//		ftp.setLocalDir("2-13");
//		Set<File> s = ftp.scanDir("s");
//		for(File f:s){
//			System.out.println(f.getAbsolutePath());
//		}
		ftp.setLocalDir("E:\\Mydocument\\GX\\广西自动气象站——分发1.0");
		ftp.setRemoteDir("m");
		File file = new File("E:\\Mydocument\\GX\\广西自动气象站——分发1.0\\2-13\\Z_SURF_C_BENN-REG_20120116214825_O_AWS_FTM.txt");
		ftp.uploadFile(file);
		File f2 = new File("E:\\Mydocument\\GX\\广西自动气象站——分发1.0\\2-13\\ss\\Z_RADI_C_BENN_20120116214826_O_ARS_FTM.txt");
		ftp.uploadFile(f2);
	}
}
